//STL
#include <iostream>
#include <fstream>
#include <stdexcept>

//Graphics
#include "Texture.h"
#include "Exceptions/InvalidGLId.h"
#include "GLUT.h"

//FreeImage
#include <FreeImage.h>

using namespace Graphics;

Texture::Texture(const std::string& file)
{
	if (file.length())
		load(file);
}

const unsigned int Texture::id() const
{
	return _id;
}

const std::string& Texture::file() const
{
	return _file;
}

const bool Texture::modulate() const
{
	return _modulate;
}

bool exists(const std::string& file)
{
	//Verify the file exists
	bool e=false;

	std::ifstream f;
	f.open(file.c_str(),std::ios::in);
	if ((f) && f.is_open())
		e=true;

	f.close();

	return e;
}

void Texture::setModulate(bool m)
{
	_modulate=m;
}

void Texture::load(const std::string& file)
{
	if (!exists(file))
	{
		std::cerr << "File '"+file+"' not found." << std::endl;
		throw new std::logic_error("File '"+file+"' not found.");
	}

	//Detect file format
	FREE_IMAGE_FORMAT formato = FreeImage_GetFileType(file.c_str(),0);
	FIBITMAP* imagen = FreeImage_Load(formato, file.c_str());
	
	FIBITMAP* temp = imagen;
	imagen = FreeImage_ConvertTo32Bits(imagen);
	FreeImage_Unload(temp);
	
	int w = FreeImage_GetWidth(imagen);
	int h = FreeImage_GetHeight(imagen);
	std::cout << "Loading texture from " + file +" (" << w << "x" << h << ")" << std::endl;
	
	GLubyte* data = new GLubyte[4*w*h];
	char* pixeles = (char*)FreeImage_GetBits(imagen);

	//FreeImage loads in BGR format, so you need to swap some bytes(Or use GL_BGR).
	for(int j= 0; j<w*h; j++)
	{
		data[j*4+0]= pixeles[j*4+2];
		data[j*4+1]= pixeles[j*4+1];
		data[j*4+2]= pixeles[j*4+0];
		data[j*4+3]= pixeles[j*4+3];
	}

	glEnable(GL_TEXTURE_2D);
	glPixelStorei(GL_UNPACK_ALIGNMENT,1);

	GLuint textureID=0;
	//Now generate the OpenGL texture object 
	glGenTextures(1, &textureID);
	if (textureID<1)
		throw new InvalidGLId(NULL,"Cannot generate texture ID for texture loaded from file: "+_file);

	_id=(unsigned int)textureID;
	glBindTexture(GL_TEXTURE_2D, textureID);

	//glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA, w, h, 0, GL_RGBA,GL_UNSIGNED_BYTE,(GLvoid*)data );
	//Create mip maps
	gluBuild2DMipmaps(GL_TEXTURE_2D, 3, w, h, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)data );
	
	//Check for errors
	GLenum e= glGetError();
	if(e!=GL_NO_ERROR)
		throw new GLError(std::string((char*)gluErrorString(e)));
}
